﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace AppConfigVerifier
{
	public class AssemblyLoader : IDisposable
	{
		//class CrossDomainDataExtensions
		//{
		//    public static Assembly GetAssembly(CrossDomainData data, AppDomain appDomain)
		//    {
		//        return appDomain.GetAssemblies().First((ass) => ass.FullName.Equals(AssemblyName.GetAssemblyName(data.Path).FullName));
		//    }
		//}

		class CrossDomainData : MarshalByRefObject
		{
			public bool HasType(string path, string typeName)
			{
				Assembly typeAssembly = Assembly.LoadFrom(path);
				return typeAssembly.GetType(typeName, false, false) != null;
			}
		}

		readonly AppDomain subDomain;

		public AssemblyLoader()
		{
			var appDomainSetup = new AppDomainSetup
			                     	{
			                     		ApplicationBase = Path.GetDirectoryName(
			                     			GetType().Assembly.Location)
			                     	};
			subDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, appDomainSetup);
			AppDomain.CurrentDomain.AssemblyResolve += subDomain_AssemblyResolve;
		}

		Assembly subDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			return Assembly.Load(args.Name);
		}

		#region IDisposable Members

		volatile bool disposed;

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		~AssemblyLoader()
		{
			Dispose(false);
		}

		void Dispose(bool disposing)
		{
			if (!disposed)
			{
				disposed = true;
				if (!disposing)
				{
				}
				AppDomain.Unload(subDomain);
				AppDomain.CurrentDomain.AssemblyResolve -= subDomain_AssemblyResolve;
			}
		}

		#endregion

		public bool HasType(string assemblyPath, string typeName)
		{
			if (disposed)
			{
				throw new InvalidOperationException("AssemblyLoader already disposed");
			}
			if (typeName == null)
			{
				throw new ArgumentNullException("typeName");
			}
			var crossData = (CrossDomainData)subDomain.CreateInstanceAndUnwrap(
				GetType().Assembly.FullName, typeof(CrossDomainData).FullName);
			return crossData.HasType(assemblyPath, typeName);
		}
	}
}
